#include "widget.h"
#include <typeinfo>

void* Widget::m_SIPLib = 0;

using namespace PortSIP;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    sipInitialized = false;
    sipRegistered = false;

    initComponents();
    initPortSIP();
}

Widget::~Widget()
{

}

void Widget::initComponents()
{
    lineEdit1 = new QLineEdit;
    lineEdit2 = new QLineEdit;
    lineEdit3 = new QLineEdit;
    lineEdit4 = new QLineEdit;

    button1 = new QPushButton;
    button2 = new QPushButton;

    combobox1 = new QComboBox;
    combobox2 = new QComboBox;
    combobox3 = new QComboBox;

    lineEdit1->setText("1002");
    lineEdit2->setText("a11223344");
    lineEdit3->setText("172.16.1.152");
    lineEdit4->setText("5060");

    button1->setText("Connect");
    button2->setText("Close");


    QFormLayout* formLayout1 = new QFormLayout;
    QHBoxLayout* hboxLayout1 = new QHBoxLayout;


    formLayout1->addRow("Username:", lineEdit1);
    formLayout1->addRow("Password:", lineEdit2);
    formLayout1->addRow("Server:", lineEdit3);
    formLayout1->addRow("Port:", lineEdit4);
    formLayout1->addRow(new QSplitter(Qt::Horizontal));
    hboxLayout1->addWidget(button1);
    hboxLayout1->addWidget(button2);
    formLayout1->addRow(hboxLayout1);
    formLayout1->addRow("Microphone:", combobox1);
    formLayout1->addRow("Speaker:", combobox2);
    formLayout1->addRow("Web Camera:", combobox3);

    setLayout(formLayout1);

    setWindowTitle("SIP Connector");

    connect(button1, SIGNAL(clicked()), this, SLOT(button1Click()));
}

void Widget::initPortSIP()
{
    m_DND = false;
    m_PCMU= false;
    m_PCMA= false;
    m_G729= false;
    m_ILBC= false;
    m_GSM= false;
    m_G722= false;
    m_SPEEX= false;
    m_SPEEX_WB= false;
    m_H263= false;
    m_H2631998= false;
    m_H264= false;
    m_AEC= false;
    m_VAD = false;
    m_AGC = false;
    m_CNG = false;
    m_ANS = false;
    m_AMRWB = false;
    m_G7221 = false;
    m_AMR = false;
    m_VP8 = false;
    m_PRACK = false;
    m_Opus = false;

    int errorCode = 0;
    TRANSPORT_TYPE transport = TRANSPORT_UDP;
    PORTSIP_LOG_LEVEL level = PORTSIP_LOG_NONE;

    qDebug() << "Initializing...";
    m_SIPLib = PortSIP_initialize(this, transport, level, NULL, 8, "PortSIP VoIP SDK 11.2", false, false, &errorCode);

    if(errorCode != 0)
    {
        QMessageBox::information(this, "Information", "PortSIP_initialize failure.");
        return;
    }

    sipInitialized = true;
    qDebug() << "Initialized the SDK.";

    int localSIPPort = SIPPORT_MIN+rand()%5000;

    char localIp[32] = { 0 };

    int nics = PortSIP_getNICNums(m_SIPLib);

    for (int i = 0; i < nics; ++i)
    {
        PortSIP_getLocalIpAddress(m_SIPLib, i, localIp, 32);
        if (!strstr(localIp, ":"))
        {
            break;
        }
    }

    if (strlen(localIp) == 0)
    {
        PortSIP_unInitialize(m_SIPLib);
        //        m_LogList.ResetContent();
        m_SIPLib = NULL;
        sipInitialized = false;

        QMessageBox::information(this, "Information", "Failed to get the local IP.");
        return;
    }

    const char* userDomain = NULL;
    const char* stunServer = NULL;
    int stunServerPort = 0;
    const char* outboundServer = NULL;
    int outboundServerPort = 0;

    errorCode = PortSIP_setUser(m_SIPLib,
                                "1002",
                                "display name",
                                "",
                                "a11223344",
                                "0.0.0.0",
                                // Use 0.0.0.0 for local IP then the SDK will choose an available local IP automatically.
                                // You also can specify a certain local IP to instead of "0.0.0.0", more details please read the SDK User Manual
                                localSIPPort,
                                userDomain,
                                "172.16.1.152",
                                5060,
                                stunServer,
                                stunServerPort,
                                outboundServer,
                                outboundServerPort);

    if(errorCode != 0)
    {
        PortSIP_unInitialize(m_SIPLib);
        //		m_LogList.ResetContent();
        m_SIPLib = NULL;
        sipInitialized = false;

        QMessageBox::information(this, "Information", "PortSIP_setUser failure.");
        return;
    }

    qDebug() << "Registering...";
    errorCode = PortSIP_registerServer(m_SIPLib, 120, 3);
    qDebug() << "Registered";

    loadDevices();

    setSRTPType();

    int rt = PortSIP_setLicenseKey(m_SIPLib, "PORTSIP_TEST_LICENSE");
    if (rt == ECoreTrialVersionLicenseKey)
    {
        //QMessageBox::information(this, "Information", "This sample was built base on evaluation PortSIP VoIP SDK, which allows only three minutes conversation. The conversation will be cut off automatically after three minutes, then you can't hearing anything. Feel free contact us at: sales@portsip.com to purchase the official version.");
    }
    else if (rt == ECoreWrongLicenseKey)
    {
        QMessageBox::information(this, "Information", "The wrong license key was detected, please check with sales@portsip.com or support@portsip.com");
    }

    //    PortSIP_setLocalVideoWindow(m_SIPLib, m_LocalVideo.m_hWnd);

    updateAudioCodecs();
    updateVideoCodecs();

    initSettings();

    setVideoResolution();
    setVideoBitrate();

    bool m_NeedRegister = true;
    if (m_NeedRegister)
    {
        errorCode = PortSIP_registerServer(m_SIPLib, 120, 3);
        if (errorCode != 0)
        {
            PortSIP_unInitialize(m_SIPLib);

            m_SIPLib = NULL;
            sipInitialized = false;

            QMessageBox::information(this, "Information", "Register to SIP server failure.");

            //            m_LogList.ResetContent();

            return;
        }

        //        SetTimer(TIMER_EVENT_AUDIO_LEVEL, 100, NULL);

        //        m_LogList.InsertString(m_LogList.GetCount(), "Registering....");
    }
}

void Widget::loadDevices()
{
    int nums = PortSIP_getNumOfPlayoutDevices(m_SIPLib);

    char deviceName[1024] = { 0 };

    //	m_SpeakersList.ResetContent();
    for (int i=0; i<nums; ++i)
    {
        PortSIP_getPlayoutDeviceName(m_SIPLib, i, deviceName, 1024);
        //		m_SpeakersList.AddString(deviceName);
        combobox1->addItem(QString(deviceName));
    }
    //	m_SpeakersList.SetCurSel(0);

    //	ZeroMemory(deviceName, 1024);
    nums = PortSIP_getNumOfRecordingDevices(m_SIPLib);
    //	m_MicrophonesList.ResetContent();
    for (int i=0; i<nums; ++i)
    {
        PortSIP_getRecordingDeviceName(m_SIPLib, i, deviceName, 1024);
        //		m_MicrophonesList.AddString(deviceName);
        combobox2->addItem(QString(deviceName));
    }
    //	m_MicrophonesList.SetCurSel(0);

    //	ZeroMemory(deviceName, 1024);
    char uniqueIdUTF8[1024] = { 0 };
    nums = PortSIP_getNumOfVideoCaptureDevices(m_SIPLib);

    //	m_CamerasList.ResetContent();
    for (int i=0; i<nums; ++i)
    {
        PortSIP_getVideoCaptureDeviceName(m_SIPLib, i,uniqueIdUTF8,1024, deviceName, 1024);
        //		m_CamerasList.AddString(deviceName);
        combobox3->addItem(QString(deviceName));
    }
    //	m_CamerasList.SetCurSel(0);

    //	m_SpeakerVolume.SetRange(0, 255);
    //	m_MicrophoneVolume.SetRange(0, 255);
    //	m_sliderVideoBitrate.SetRange(100,2000);
    //	m_sliderVideoBitrate.SetPos(300);

    //	int audioVolume = PortSIP_getMicVolume(m_SIPLib);
    //	m_MicrophoneVolume.SetPos(audioVolume);

    //	audioVolume = PortSIP_getSpeakerVolume(m_SIPLib);
    //	m_SpeakerVolume.SetPos(audioVolume);

    //	m_progSpeakerLevel.SetRange(0, 100);
    //	m_progMicroLevel.SetRange(0, 100);

    //	m_LineList.AddString("Line - 1");
    //	m_LineList.AddString("Line - 2");
    //	m_LineList.AddString("Line - 3");
    //	m_LineList.AddString("Line - 4");
    //	m_LineList.AddString("Line - 5");
    //	m_LineList.AddString("Line - 6");
    //	m_LineList.AddString("Line - 7");
    //	m_LineList.AddString("Line - 8");
    //	m_LineList.SetCurSel(0);

    m_PCMA = TRUE;
    m_PCMU = TRUE;
    m_G729 = TRUE;

    m_H264 = TRUE;

    m_AEC = TRUE;
    m_VAD = TRUE;
    m_AGC = TRUE;
    m_CNG = TRUE;
    m_ANS = TRUE;

    //	m_cmbSIPTransport.SetCurSel(0);
    //	m_cmbSRTPMode.SetCurSel(0);
    //	m_cmbVideoResolution.SetCurSel(1);
    //	UpdateData(FALSE);
    //	return true;
}

void Widget::setSRTPType()
{
    if (sipInitialized == false)
    {
        return;
    }

    SRTP_POLICY srtpPolicy = SRTP_POLICY_NONE;

    //	switch (m_cmbSRTPMode.GetCurSel())
    //	{
    //	case 0:
    //		srtpPolicy = SRTP_POLICY_NONE;
    //		break;
    //	case 1:
    //		srtpPolicy = SRTP_POLICY_PREFER;
    //		break;
    //	case 2:
    //		srtpPolicy = SRTP_POLICY_FORCE;
    //		break;
    //	}

    PortSIP_setSrtpPolicy(m_SIPLib, srtpPolicy);
}

void Widget::updateAudioCodecs()
{
    if (sipInitialized == false)
    {
        return;
    }

    PortSIP_clearAudioCodec(m_SIPLib);



    if (m_PCMU)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_PCMU);
    }

    if (m_PCMA)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_PCMA);
    }
    if (m_G729)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_G729);
    }
    if (m_ILBC)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_ILBC);
    }
    if (m_GSM)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_GSM);
    }

    if (m_G722)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_G722);
    }
    if (m_SPEEX)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_SPEEX);
    }

    if (m_SPEEX_WB)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_SPEEXWB);
    }

    if (m_AMR)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_AMR);
    }

    if (m_AMRWB)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_AMRWB);
    }
    if (m_G7221)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_G7221);
    }

    if (m_Opus)
    {
        PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_OPUS);
    }


    PortSIP_addAudioCodec(m_SIPLib, AUDIOCODEC_DTMF);
}

void Widget::updateVideoCodecs()
{
    if (sipInitialized == false)
    {
        return;
    }

    PortSIP_clearVideoCodec(m_SIPLib);


    //UpdateData(TRUE);

    if (m_H263)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_H263);
    }

    if (m_H2631998)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_H263_1998);
    }

    if (m_H264)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_H264);
    }

    if (m_VP8)
    {
        PortSIP_addVideoCodec(m_SIPLib, VIDEO_CODEC_VP8);
    }
}

void Widget::initSettings()
{
    if (sipInitialized == false)
    {
        return;
    }

    //UpdateData(TRUE);

    PortSIP_enableAEC(m_SIPLib, m_AEC==TRUE);
    PortSIP_enableCNG(m_SIPLib, m_CNG==TRUE);
    PortSIP_enableAGC(m_SIPLib, m_AGC==TRUE);
    PortSIP_enableANS(m_SIPLib, m_ANS==TRUE);
    PortSIP_enableVAD(m_SIPLib, m_VAD==TRUE);

    PortSIP_setDoNotDisturb(m_SIPLib, m_DND==TRUE);
}

void Widget::setVideoResolution()
{
    if (sipInitialized == false)
    {
        return;
    }

    VIDEO_RESOLUTION videoResolution = VIDEO_CIF;
    /*
    switch (m_cmbVideoResolution.GetCurSel())
    {
    case 0:
        videoResolution = VIDEO_QCIF;
        break;
    case 1:
        videoResolution = VIDEO_CIF;
        break;
    case 2:
        videoResolution = VIDEO_VGA;
        break;
    case 3:
        videoResolution = VIDEO_SVGA;
        break;
    case 4:
        videoResolution = VIDEO_XVGA;
        break;
    case 5:
        videoResolution = VIDEO_720P;
        break;
    case 6:
        videoResolution = VIDEO_QVGA;
        break;
    }
    */

    PortSIP_setVideoResolution(m_SIPLib,videoResolution);
}

void Widget::setVideoBitrate()
{
    if (sipInitialized == false)
    {
        return;
    }

    if(sipInitialized)
    {
        //PortSIP_setVideoBitrate(m_SIPLib,m_sliderVideoBitrate.GetPos());
    }
    //m_strBitrate.Format("%dKbps",m_sliderVideoBitrate.GetPos());
    //UpdateData(FALSE);
}

void Widget::button1Click()
{
//    updateAudioCodecs();
//    updateVideoCodecs();

//    updatePrackSetting();

//    if (PortSIP_isAudioCodecEmpty(m_SIPLib) == true)
//    {
//        initDefaultAudioCodecs();
//    }

//    stringstream to;
//    to << (LPTSTR)(LPCTSTR)m_PhoneNumber;



//    bool hasSDP = true;  // Usually to make the 3PCC, you need to make an invite without SDP
//    if (m_CallSDP)
//    {
//        hasSDP = false;
 //   }


    PortSIP_setAudioDeviceId(m_SIPLib, 0, 0);


    // The callee MUST likes sip:number@sip.portsip.com
    int errorCode = 0;
//    bool makeVideoCall = false;
//    if (m_MakeVideoCall)
//    {
//        makeVideoCall = true;
//    }

    long sessionId = PortSIP_call(m_SIPLib, "sip:1003@172.16.1.152", false, false);
    if (sessionId <= 0)
    {
        if(errorCode != 0)
        {
            //showErrorMessage(errorCode);
        }
        QMessageBox::information(this, "Information", "PortSIP_call failure.");
        return;
    }

//    PortSIP_setRemoteVideoWindow(m_SIPLib, sessionId, m_RemoteVideo.m_hWnd);

//    m_SessionArray[m_ActiveLine].setSessionId(sessionId);
//    m_SessionArray[m_ActiveLine].setSessionState(true);


//    stringstream text;
//    text << "Calling on line " << m_ActiveLine << "";

//    m_LogList.InsertString(m_LogList.GetCount(), text.str().c_str());
}

void Widget::onMessage(void *parameters)
{
    if (parameters == NULL)
    {
        qDebug() << "NULL";
        return;
    }

    ICallbackParameters* parameter = reinterpret_cast<ICallbackParameters *>(parameters);

//    int eventType = parameter->getEventType();

    char* c = (char*)parameters;

    int eventType = ((int*)(&c[24]))[0];

    int* in = (int*)parameters;



    switch(eventType)
    {
    case SIP_UNKNOWN:
        break;

    case SIP_REGISTER_SUCCESS:
        qDebug() << "SIP_REGISTER_SUCCESS";
        break;

    case SIP_REGISTER_FAILURE:
        qDebug() << "SIP_REGISTER_FAILURE";
        break;

    case SIP_INVITE_INCOMING:
    {
        qDebug() << "SIP_INVITE_INCOMING";

        for (int i=0; i<1024*4; i++)
        {
            //if (c[i] !=0)
            printf("%d ", c[i]);
        }
        puts("\n---");
    //    printf("%d\n", eventType);
        fflush(stdout);

        int rt = PortSIP_answerCall(Widget::m_SIPLib, 1, false);


     }
        break;

    case SIP_INVITE_TRYING:
        qDebug() << "SIP_INVITE_TRYING";
        break;

    case SIP_INVITE_SESSION_PROGRESS:
        qDebug() << "SIP_INVITE_SESSION_PROGRESS";
        break;

    case SIP_INVITE_RINGING:
        qDebug() << "SIP_INVITE_RINGING";
        break;

    case SIP_INVITE_ANSWERED:
        break;

    case SIP_INVITE_FAILURE:
        break;

    case SIP_INVITE_UPDATED:
        break;

    case SIP_INVITE_CONNECTED:
        break;

    case SIP_INVITE_BEGINING_FORWARD:
        break;

    case SIP_INVITE_CLOSED:
        break;

    case SIP_REMOTE_HOLD:
        break;

    case SIP_REMOTE_UNHOLD:
        break;

    case SIP_RECEIVED_REFER:
        break;

    case SIP_REFER_ACCEPTED:
        break;

    case SIP_REFER_REJECTED:
        break;

    case SIP_TRANSFER_TRYING:
        break;

    case SIP_TRANSFER_RINGING:
        break;

    case SIP_ACTV_TRANSFER_SUCCESS:
        break;

    case SIP_ACTV_TRANSFER_FAILURE:
        break;

    case SIP_RECEIVED_SIGNALING:
        break;

    case SIP_SENDING_SIGNALING:
        break;

    case SIP_WAITING_VOICEMESSAGE:
        break;

    case SIP_WAITING_FAXMESSAGE:
        break;

    case SIP_RECV_DTMFTONE:
        break;

    case SIP_PRESENCE_RECV_SUBSCRIBE:
        break;

    case SIP_PRESENCE_ONLINE:
        break;

    case SIP_PRESENCE_OFFLINE:
        break;

    case SIP_RECV_OPTIONS:
        break;

    case SIP_RECV_INFO:
        break;

    case SIP_RECV_MESSAGE:
        break;

    case SIP_RECV_OUTOFDIALOG_MESSAGE:
        break;

    case SIP_SEND_MESSAGE_SUCCESS:
        break;

    case SIP_SEND_MESSAGE_FAILURE:
        break;

    case SIP_SEND_OUTOFDIALOG_MESSAGE_SUCCESS:
        break;

    case SIP_SEND_OUTOFDIALOG_MESSAGE_FAILURE:
        break;

    case SIP_PLAY_AUDIO_FILE_FINISHED:
        break;

    case SIP_PLAY_VIDEO_FILE_FINISHED:
        break;
    }
}
